home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / util / libs / halt.lzh / halt / shutdown.c < prev    next >
C/C++ Source or Header  |  1995-10-06  |  11KB  |  439 lines

  1. /*
  2.    shutdown.c --- shutdown frontend.
  3.  
  4.    (c) Copyright 1995 SHW Wabnitz
  5.    Written by Bernhard Fastenrath (fasten@shw.com)
  6.  
  7.    This file may be distributed under the terms
  8.    of the GNU General Public License.
  9. */
  10.  
  11. #include <dos.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <exec/types.h>
  16. #include <exec/memory.h>
  17. #include <intuition/intuition.h>
  18. #include <proto/exec.h>
  19. #include <proto/intuition.h>
  20.  
  21. #if defined (__GNUC__)
  22. #include "halt_inline.h"
  23. #else
  24. #include "halt_pragmas.h"
  25. #endif
  26. #include "halt.h"
  27.  
  28. int GoDown (int now);
  29.  
  30. #define SIGBREAKF_MASK ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | \
  31.              SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
  32.  
  33. struct IntuitionBase *IntuitionBase = NULL;
  34. struct Library *HaltBase = NULL;
  35. ShutdownMessage *Smsg = NULL;
  36. ShutdownContext SContext;
  37. struct timerequest *TimerReq = NULL;
  38. struct MsgPort *TimerPort = NULL;
  39. struct MsgPort *ReplyPort = NULL;
  40. struct MsgPort *ShutdownPort = NULL;
  41. ULONG TimerMask;
  42. ULONG TimerErr = 1;
  43. ULONG ShutdownMask;
  44. ULONG ReplyMask;
  45. ULONG WaitMask;
  46. int point_of_no_return = 0;
  47. int ExpectTimeout = 0;
  48. char *ShutdownPortname = "Shutdown";
  49. int SpNameLen;
  50. ULONG ShutdownFlags;
  51. ULONG BroadcastTimeout = 5;
  52. char *CantAllocatePort = "Can't allocate message port.\n";
  53. char *ShutdownCancelled = "shutdown cancelled.\n";
  54. char *OutOfMemory = "Out of memory.\n";
  55. char *SorryTooLate = "Too late to stop shutdown.\n";
  56. int MessageTimedOut = 0;
  57. int HaltFlag = 1, SyncTime = 5;
  58. int FastBoot = 0;
  59. int Error;
  60. char *optarg = NULL;
  61.  
  62. int
  63. getopt (int argc, char *argv[], char *opts)
  64. {
  65.   static int pos = 0;
  66.   char *c;
  67.  
  68.   while (++pos < argc && argv[pos][0] != '-');
  69.   if (pos >= argc)
  70.     return -1;
  71.   if ((c = strchr (opts, (int) argv[pos][1])) == 0)
  72.     return (int) '?';
  73.   if (*(c+1) != ':')
  74.     return (int) *c;
  75.   if (strlen (argv[pos]) > 2)
  76.     optarg = argv[pos] + 2;
  77.   else if (pos+1 < argc)
  78.     optarg = argv[pos+1];
  79.   else
  80.     return (int) '?';
  81.   return (int) *c;
  82. }
  83.  
  84. ShutdownMessage *
  85. AllocShutdownMessage ()
  86. {
  87.   ShutdownNode *node;
  88.  
  89.   if (!(node = (ShutdownNode *)
  90.     AllocMem (sizeof (ShutdownNode), MEMF_PUBLIC | MEMF_CLEAR)))
  91.   {
  92.     return NULL;
  93.   }
  94.   node -> sn_Msg.sm_Msg.mn_ReplyPort = ReplyPort;
  95.   node -> sn_Msg.sm_Msg.mn_Length = sizeof (ShutdownMessage);
  96.   node -> sn_Msg.sm_Context = &SContext;
  97.   AddTail (&SContext.sc_List, (struct Node *) node);
  98.   return &node -> sn_Msg;
  99. }
  100.  
  101. ULONG
  102. PutAndGet (ShutdownMessage *smsg, char *portname)
  103. {
  104.   struct MsgPort *prt;
  105.  
  106.   Forbid ();
  107.   if (prt = FindPort (portname))
  108.   {
  109.     PutMsg (prt, (struct Message *) smsg);
  110.     Permit ();
  111.     do
  112.       WaitPort (ReplyPort);
  113.     while (!GetMsg (ReplyPort));
  114.   }
  115.   else
  116.     Permit ();
  117.   return ((ULONG) prt);
  118. }
  119.  
  120. void
  121. CleanUp (char *error)
  122. {
  123.   ShutdownNode *node, *next;
  124.  
  125.   if (error)
  126.     printf (error);
  127.   if (!TimerErr)
  128.     CloseDevice ((struct IORequest *) TimerReq);
  129.   if (TimerReq)
  130.     DeleteIORequest (TimerReq);
  131.   if (TimerPort)
  132.     DeleteMsgPort (TimerPort);
  133.   if (ReplyPort)
  134.     DeleteMsgPort (ReplyPort);
  135.   if (ShutdownPort)
  136.   {
  137.     if (ShutdownPort -> mp_Node.ln_Name)
  138.       FreeMem (ShutdownPort -> mp_Node.ln_Name, SpNameLen);
  139.     RemPort (ShutdownPort);
  140.     DeleteMsgPort (ShutdownPort);
  141.   }
  142.   node = (ShutdownNode *) SContext.sc_List.lh_Head;
  143.   while (next = (ShutdownNode *) node -> sn_MinNode.mln_Succ)
  144.   {
  145.     FreeMem (node, sizeof (ShutdownNode));
  146.     node = next;
  147.   }
  148.   if (HaltBase)
  149.     CloseLibrary (HaltBase);
  150.   if (IntuitionBase)
  151.     CloseLibrary ((struct Library *) IntuitionBase);  
  152.   exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
  153. }
  154.  
  155. int
  156. CancelShutdown (void)
  157. {
  158.   if (point_of_no_return)
  159.     return 0;
  160.  
  161.   if (SContext.sc_TimeOuts)
  162.   {
  163.     printf ("Shutdown cannot exit, there are still %d unreplied messages.\n",
  164.         SContext.sc_TimeOuts);
  165.     return 0;
  166.   }
  167.   if (ExpectTimeout == 1)
  168.   {
  169.     printf ("Press CTRL-C to abort the following "
  170.         "cancel message before it times out.\n");
  171.     ExpectTimeout = 2;
  172.   }
  173.   if (Smsg)
  174.   {
  175.     BroadcastTimeout = 0;
  176.     Smsg -> sm_Status = SHUTDOWN_ABORT;
  177.     BroadcastShutdownMsg ();
  178.   }
  179.   CleanUp (ShutdownCancelled);
  180. }
  181.  
  182. int
  183. BroadcastShutdownMsg ()
  184. {
  185.   if (BroadcastTimeout)
  186.   {
  187.     TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
  188.     TimerReq -> tr_time.tv_secs  = BroadcastTimeout;
  189.     TimerReq -> tr_time.tv_micro = 0;
  190.     SendIO ((struct IORequest *) TimerReq);
  191.   }
  192.   Smsg -> sm_Flags = ShutdownFlags;
  193.   ShutdownStatus (Smsg);
  194.   if (Smsg -> sm_Flags & SDMF_SIG_MASK)
  195.   {
  196.     printf ("Warning: shutdown message timed out.\n");
  197.     if (!ExpectTimeout)
  198.       ExpectTimeout = 1;
  199.   }
  200.   if (Smsg -> sm_Flags & SDMF_CTRL_C)
  201.   {
  202.     /* We didn't receive a timeout yet but a CTRL-C during a
  203.        broadcast is unlikely if there was no timeout ahead.
  204.     */
  205.     if (!ExpectTimeout)
  206.       ExpectTimeout = 1;
  207.   }
  208.   if (BroadcastTimeout)
  209.   {
  210.     if (Smsg -> sm_Flags & SDMF_SIG_MASK)
  211.     {
  212.       RemShutdownPort (Smsg -> sm_Context -> sc_Port);
  213.  
  214.       while (!(Smsg = AllocShutdownMessage ()))
  215.     Delay (50); /* Better ideas welcome ... */
  216.     }
  217.     else
  218.       AbortIO ((struct IORequest *) TimerReq);
  219.     WaitIO ((struct IORequest *) TimerReq);
  220.     SetSignal (0L, TimerMask);
  221.   }
  222.   if (!point_of_no_return)
  223.   {
  224.     if (Smsg -> sm_Flags & SDMF_CANCEL)
  225.       CancelShutdown ();
  226.   }
  227. }
  228.  
  229. void
  230. AbortableDelay (int seconds)
  231. {
  232.   ShutdownMessage *sm;
  233.   int abort = 0;
  234.   ULONG mask;
  235.  
  236.   TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
  237.   TimerReq -> tr_time.tv_secs  = seconds;
  238.   TimerReq -> tr_time.tv_micro = 0;
  239.   SendIO ((struct IORequest *) TimerReq);
  240.  
  241.   while (1)
  242.   {
  243.     mask = Wait (WaitMask);
  244.     if (mask & ShutdownMask)
  245.     {
  246.       do
  247.         WaitPort (ShutdownPort);
  248.       while (!(sm = (ShutdownMessage *) GetMsg (ShutdownPort)));
  249.       if (sm -> sm_Status == SHUTDOWN_ABORT)
  250.     if (point_of_no_return)
  251.       sm -> sm_Status = SHUTDOWN_UMOUNT;
  252.     else
  253.           abort = 1;
  254.       ReplyMsg ((struct Message *) sm);
  255.     }
  256.     if (mask & ReplyMask) /* late reply */
  257.     {
  258.       if (GetMsg (ReplyPort))
  259.     SContext.sc_TimeOuts --;
  260.     }
  261.     if (mask & SIGBREAKF_MASK || abort)
  262.     {
  263.       if (point_of_no_return)
  264.       {
  265.     printf (SorryTooLate);
  266.     continue;
  267.       }
  268.       if (!(mask & TimerMask))
  269.         AbortIO ((struct IORequest *) TimerReq);
  270.       WaitIO ((struct IORequest *) TimerReq);
  271.       SetSignal (0L, TimerMask);
  272.  
  273.       if (mask & SIGBREAKF_CTRL_C || abort)
  274.       {
  275.     if (mask & SIGBREAKF_CTRL_C && !ExpectTimeout)
  276.       printf ("CTRL-C\n");
  277.     CancelShutdown ();
  278.     printf ("Timer stopped, press CTRL-E or CTRL-F to reboot.\n");
  279.       }
  280.       if (mask & SIGBREAKF_CTRL_D) /* CTRL-D: speed up */
  281.       {
  282.     printf ("CTRL-D\n");
  283.     return;
  284.       }
  285.       if (!FastBoot)
  286.       {
  287.     FastBoot = 1;
  288.     if (mask & SIGBREAKF_CTRL_E) /* CTRL-E: fast reboot */
  289.         {
  290.       printf ("CTRL-E\n");
  291.       GoDown (0);
  292.         }
  293.     if (mask & SIGBREAKF_CTRL_F) /* CTRL-F: very fast reboot */
  294.     {
  295.       printf ("CTRL-F\n");
  296.       GoDown (1);
  297.     }
  298.       }
  299.       else
  300.     return;
  301.     }
  302.     if (mask & TimerMask) /* done waiting */
  303.       return;
  304.   }
  305. }
  306.  
  307. int
  308. main (int argc, char *argv[])
  309. {
  310.   int cancel_flag = 0, abortable_flag = 1;
  311.   int shutdown_time = 10, shutdown_interval;
  312.   int opt;
  313.  
  314.   bzero (&SContext, sizeof (ShutdownContext));
  315.   NewList (&SContext.sc_List);
  316.   SetTaskPri (FindTask (0L), 10);
  317.  
  318.   while ((opt = getopt (argc, argv, "chnrs:t:T:")) != -1)
  319.     switch (opt)
  320.     {
  321.       case 'n': abortable_flag = 0; break;
  322.       case 'r': HaltFlag = 0; break;
  323.       case 'h': HaltFlag = 1; break;
  324.       case 't': shutdown_time = atoi (optarg); break;
  325.       case 's': SyncTime = atoi (optarg); break;
  326.       case 'c': cancel_flag = 1; break;
  327.       case 'T': BroadcastTimeout = atoi (optarg); break;
  328.       default:
  329.         printf ("Usage: %s [-chnr] [-t <time>] [-s <sync time>] [-T <timeout>].\n", argv[0]);
  330.     exit (EXIT_FAILURE);
  331.     }
  332.  
  333.   if (HaltFlag)
  334.     IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37);
  335.   if (!(HaltBase = OpenLibrary ("halt.library", 0)))
  336.     CleanUp ("Failed to open halt.library.\n");
  337.  
  338.   if (!(ReplyPort = CreateMsgPort ()))
  339.     CleanUp (CantAllocatePort);
  340.   ReplyMask = 1 << ReplyPort -> mp_SigBit;
  341.   if (!(Smsg = AllocShutdownMessage ()))
  342.     CleanUp (OutOfMemory);
  343.   if (abortable_flag)
  344.     ShutdownFlags = SDMF_ABORTABLE;
  345.  
  346.   /* open timer device */
  347.   if (!(TimerPort = CreateMsgPort ()))
  348.     CleanUp (CantAllocatePort);
  349.   if (!(TimerReq = (struct timerequest *)
  350.     CreateIORequest (TimerPort, sizeof (struct timerequest))))
  351.     CleanUp (OutOfMemory);
  352.   if (TimerErr = OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerReq, 0))
  353.     CleanUp ("Can't open timer device.\n");
  354.   Smsg -> sm_Context -> sc_Mask = TimerMask = 1 << TimerPort -> mp_SigBit;
  355.  
  356.   if (cancel_flag)
  357.   {
  358.     Smsg -> sm_Status = SHUTDOWN_ABORT;
  359.     if (!PutAndGet (Smsg, ShutdownPortname))
  360.       CleanUp ("Shutdown is not running.\n");
  361.     if (Smsg -> sm_Status == SHUTDOWN_UMOUNT)
  362.       CleanUp (SorryTooLate);
  363.     CleanUp (ShutdownCancelled);
  364.   }
  365.  
  366.   /* don't start shutdown twice */
  367.   Forbid ();
  368.   if (FindPort (ShutdownPortname))
  369.   {
  370.     Permit ();
  371.     CleanUp ("Shutdown is already running.\n");
  372.   }
  373.   Permit ();
  374.   if (!(ShutdownPort = CreateMsgPort ()))
  375.     CleanUp (CantAllocatePort);
  376.   if (!(ShutdownPort -> mp_Node.ln_Name =
  377.     AllocMem (SpNameLen = strlen (ShutdownPortname) + 1, MEMF_PUBLIC)))
  378.     CleanUp (OutOfMemory);
  379.   bcopy (ShutdownPortname, ShutdownPort -> mp_Node.ln_Name, SpNameLen);
  380.   ShutdownPort -> mp_Node.ln_Pri = 0;
  381.   AddPort (ShutdownPort);
  382.   ShutdownMask = 1 << ShutdownPort -> mp_SigBit;
  383.   WaitMask = ReplyMask | ShutdownMask | TimerMask | SIGBREAKF_MASK;
  384.  
  385.   while (shutdown_time > 5)
  386.   {
  387.     shutdown_interval = shutdown_time / 2;
  388.     printf ("The system is going down in %d seconds.\n", shutdown_time);
  389.     Smsg -> sm_Status   = SHUTDOWN_WARN;
  390.     Smsg -> sm_TimeLeft = shutdown_time;
  391.     BroadcastShutdownMsg ();
  392.     AbortableDelay (shutdown_interval);
  393.     shutdown_time -= shutdown_interval;
  394.   }
  395.   GoDown (0);
  396. }
  397.  
  398. int
  399. GoDown (int now)
  400. {
  401.   struct EasyStruct es = {
  402.     sizeof (struct EasyStruct), 0, "AmigaDOS", "The system is halted", "Ok"
  403.   };
  404.  
  405.   if (!now)
  406.   {
  407.     /* last warning */
  408.     Smsg -> sm_Status   = SHUTDOWN_NOW;
  409.     Smsg -> sm_TimeLeft = 5;
  410.     BroadcastShutdownMsg ();
  411.     printf ("The system is going down in 5 seconds.\n");
  412.     AbortableDelay (5);
  413.  
  414.     /* too late for writing */
  415.     Smsg -> sm_Status   = SHUTDOWN_UMOUNT;
  416.     Smsg -> sm_TimeLeft = 0;
  417.     BroadcastShutdownMsg ();
  418.   }
  419.   point_of_no_return = 1;
  420.   ShutdownFlags &= ~SDMF_ABORTABLE;
  421.  
  422.   printf ("The system is going down, unmounting filesystems.\n");
  423.   Unmount (NULL);
  424.   AbortableDelay (SyncTime);
  425.  
  426.   if (!now) /* all done, who turns off the light? */
  427.   {
  428.     Smsg -> sm_Status   = SHUTDOWN_HALT;
  429.     Smsg -> sm_TimeLeft = 0;
  430.     BroadcastShutdownMsg ();
  431.   }
  432.   printf ("The system is halted.\n");
  433.  
  434.   if (IntuitionBase)
  435.     BuildEasyRequest (NULL, &es, NULL);
  436.   Delay (10); /* wait 0.5 seconds */
  437.   Reboot (HaltFlag); /* 0 = reboot, 1 = halt */
  438. }
  439.